package com.qx.chat.rtc.signalmaster;

import java.io.File;
import java.io.FileInputStream;
import java.util.Collection;
import java.util.Properties;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.listener.ConnectListener;
import com.corundumstudio.socketio.listener.DataListener;
import com.qx.chat.system.util.JsonUtil;

public class RtcSignalMaster {
	private static Logger logger = Logger.getLogger(RtcSignalMaster.class);
	/**
	 * 同步线程
	 */
	private static Thread thread = new Thread();
	static SocketIOServer server;
	private static int roomMaxClients = 0;
	private static String FILE_NAME = "rtcSignalMaster.properties";

	public static void start() throws Exception {
		Properties prop = new Properties();
		FileInputStream fis = new FileInputStream(RtcSignalMaster.class.getClassLoader().getResource(FILE_NAME).getPath());
		prop.load(fis);
		thread.start();
		Configuration config = new Configuration();
		config.setHostname(prop.getProperty("hostname"));
		config.setPort(Integer.parseInt(prop.getProperty("port")));

		server = new SocketIOServer(config);

		server.addConnectListener(new ConnectListener() {
			@Override
			public void onConnect(SocketIOClient client) {
				String screen = prop.getProperty("screen");
				client.set("screen", Boolean.parseBoolean(screen));
				String video = prop.getProperty("video");
				client.set("video", Boolean.parseBoolean(video));
				String audio = prop.getProperty("audio");
				client.set("audio", Boolean.parseBoolean(audio));
				String stunStr = prop.getProperty("stunservers");
				client.sendEvent("stunservers", JSONArray.parseArray(stunStr));
				String turnStr = prop.getProperty("turnservers");
				client.sendEvent("turnservers", JSONArray.parseArray(turnStr));
			}
		});
		server.addEventListener("message", Object.class, new DataListener<Object>() {
			@Override
			public void onData(SocketIOClient client, Object data, AckRequest ackRequest) {
				String json = JsonUtil.toJson(data);
				JSONObject jo = JSONObject.parseObject(json);
				UUID uuid = UUID.fromString(jo.getString("to"));
				SocketIOClient toClient = server.getClient(uuid);
				if (toClient != null) {
					UUID clientId = client.getSessionId();
					jo.remove("from");
					jo.put("from", clientId);
					toClient.sendEvent("message", jo);
				}
			}
		});
		server.addEventListener("shareScreen", String.class, new DataListener<String>() {
			@Override
			public void onData(SocketIOClient client, String data, AckRequest ackRequest) {
				client.set("screen", true);
			}
		});
		server.addEventListener("unshareScreen", String.class, new DataListener<String>() {
			@Override
			public void onData(SocketIOClient client, String data, AckRequest ackRequest) {
				client.set("screen", false);
				removeFeed(client, "screen");
			}
		});
		server.addEventListener("join", String.class, new DataListener<String>() {
			@Override
			public void onData(SocketIOClient client, String data, AckRequest ackRequest) {
				join(client, data, ackRequest);
			}
		});
		server.addEventListener("disconnect", String.class, new DataListener<String>() {
			@Override
			public void onData(SocketIOClient client, String data, AckRequest ackRequest) {
				removeFeed(client, null);
			}
		});
		server.addEventListener("leave", String.class, new DataListener<String>() {
			@Override
			public void onData(SocketIOClient client, String data, AckRequest ackRequest) {
				removeFeed(client, null);
			}
		});
		server.addEventListener("create", String.class, new DataListener<String>() {
			@Override
			public void onData(SocketIOClient client, String name, AckRequest ackRequest) {
				if (StringUtils.isBlank(name)) {
					name = UUID.randomUUID().toString();
				}
				Collection<SocketIOClient> clients = server.getNamespace("/").getRoomOperations(name).getClients();
				// check if exists
				if (clients != null && clients.size() > 0) {
					if (ackRequest.isAckRequested()) {
						ackRequest.sendAckData("taken");
					}
				} else {
					join(client, name, ackRequest);
					if (ackRequest.isAckRequested()) {
						ackRequest.sendAckData(null, name);
					}
				}
			}
		});
		server.addEventListener("trace", String.class, new DataListener<String>() {
			@Override
			public void onData(SocketIOClient client, String data, AckRequest ackRequest) {
			}
		});

		logger.info(">>>>> 启动RtcSignalMaster 。。。");

		server.start();

	}

	public static void removeFeed(SocketIOClient client, String type) {
		String room = client.get("room");
		if (!StringUtils.isBlank(room)) {
			server.getRoomOperations(room).sendEvent("remove",
					"{id: '" + client.getSessionId() + "',type: '" + type + "'}");
			if (!StringUtils.isBlank(type)) {
				client.leaveRoom(room);
				client.set("room", null);
			}
		}
	}

	public static void join(SocketIOClient client, String room, AckRequest ackRequest) {
		// sanity check
		if (!StringUtils.isBlank(room)) {
			// check if maximum number of clients reached
			if (roomMaxClients != 0 && roomMaxClients > 0 && clientsInRoom(room) >= roomMaxClients) {
				ackRequest.sendAckData("full");
			} else {
				// leave any existing rooms
				removeFeed(client, null);
				ackRequest.sendAckData(null, JSONObject.parseObject(describeRoom(room)));
				client.joinRoom(room);
				client.set("room", room);
			}
		}
	}

	public static String describeRoom(String name) {
		Collection<SocketIOClient> clients = server.getRoomOperations(name).getClients();
		JSONObject j = new JSONObject();
		JSONObject jo = new JSONObject();
		for (SocketIOClient c : clients) {
			JSONObject jores = new JSONObject();
			jores.put("screen", c.get("screen"));
			jores.put("video", c.get("video"));
			jores.put("audio", c.get("audio"));
			jo.put(c.getSessionId().toString(), jores);
		}
		j.put("clients", jo);
		String jsonString = j.toJSONString();
		jsonString = jsonString.replaceAll("\"", "'");
		return jsonString;
	}

	public static int clientsInRoom(String name) {
		return server.getRoomOperations(name).getClients().size();
	}

	/**
	 * 停止AkkaSystem，
	 */
	public void close() {
		server.stop();
	}
}